/*
 * @Author: zhaiyujia
 * @Date: 2022-04-25 00:05:02
 * @LastEditors: zhaiyujia
 * @LastEditTime: 2022-11-28 15:31:48
 * @Description: Arduino-STC
 */

#ifndef _Arduino_h
#define _Arduino_h

#include "ecbm_core.h"

// =========================================================== Config
#define MILLIS_EN 0
#define EEPROM_EN 0
#define UART_SEND_EN 1
#define UART_RECEIVE_EN 0
#define UART_PRINTF_EN 0
#define FUNC_STRING_EN 1
#define FUNC_MEMORY_EN 0
#define ANALOG_READ_EN 0
#define ANALOG_WRITE_EN 0
// =========================================================== Type
#define bool u8
#define uint8_t u8
#define uint16_t u16
#define uint32_t u32

#define delay(ms) delay_ms(ms)
#define delayMicroseconds(us) delay_us(us)
// =========================================================== GPIO
#define LOW 0x0
#define HIGH 0x1

#define GPIO_PU 0        // 设置IO为弱上拉。
#define GPIO_HZ 1        // 设置IO为高阻态。
#define GPIO_OD 2        // 设置IO为开漏。
#define GPIO_PP 3        // 设置IO为推挽。
#define GPIO_IN GPIO_PU  // 输入模式设定为弱上拉。
#define GPIO_OUT GPIO_PP // 输出模式设定为推挽。
#define INPUT GPIO_HZ    /// GPIO_IN
#define OUTPUT GPIO_OUT

#define pinMode gpio_mode
#define digitalWrite gpio_out
#define digitalRead gpio_in
// =========================================================== Analog
#if ANALOG_READ_EN
#if (ECBM_ADC_LIB_EN && ECBM_ADC_CH0) == 0
#error Config error, please modify the settings!
#endif
#define analogRead adc_read
#define analogReadVoltage adc_voltage
#endif
#if ANALOG_WRITE_EN
#if (ECBM_PCA_LIB_EN && ECBM_PCA0_EN && ECBM_PCA1_EN && ECBM_PCA2_EN) == 0
#error Config error, please modify the settings!
#endif
#define A0 0 // P1.1->CCP0
#define A1 1 // P1.1->CCP1
#define A2 2 // P1.1->CCP2
// pin = A0~A2, duty=0~1000
#define analogWrite(pin, duty) pca_set_duty(pin, duty)
#endif
// =========================================================== Serial
// -------------------------------------- >> Serial Send
#if UART_SEND_EN
#if (ECBM_UART_LIB_EN && ECBM_UART1_EN) == 0
#error Config error, please modify the settings!
#endif
#define Serial_begin(baud) \
    uart_init();           \
    uart_set_baud(1, baud)

#define Serial_write(c) uart_char(1, c)
#define Serial_print(str) uart_string(1, str)
// #define Serial_println(str) uart_string(1, str##"\r\n")
#define Serial_println(str)     \
    do                          \
    {                           \
        uart_string(1, str);    \
        uart_string(1, "\r\n"); \
    } while (0)
#endif // UART_SEND_EN
// -------------------------------------- >> Serial Printf
#if UART_PRINTF_EN
#if (UART_SEND_EN) == 0
#error Config error, please modify the settings!
#endif
void uart1_printf(const char *str, ...)
{
    char xdata buf[ECBM_UART_PRINTF_BUF_MAX];
    va_list vp;
    va_start(vp, str);

    vsprintf(buf, str, vp);
    va_end(vp);
    uart_string(1, buf);
}
#define Serial_printf uart1_printf
#endif // UART_PRINTF_EN
// -------------------------------------- >> Serial Receive
#if UART_RECEIVE_EN
#if (ECBM_UART_LIB_EN && ECBM_UART1_EN && ECBM_UART1_RECEIVE_CALLBACK_EN) == 0
#error Config error, please modify the settings!
#endif
#define SERIAL_RX_BUFFER_SIZE 64 // 256
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
uint8_t _rx_buffer_head = 0;
uint8_t _rx_buffer_tail = 0;
void uart1_receive_callback()
{
    unsigned char c = UART1_GET_REG_SBUF;
    uint8_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
    if (i != _rx_buffer_tail)
    {
        _rx_buffer[_rx_buffer_head] = c;
        _rx_buffer_head = i;
    }
}
#define Serial_available() ((SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_RX_BUFFER_SIZE)
int Serial_peek(void)
{
    if (_rx_buffer_head == _rx_buffer_tail)
        return -1;
    else
        return _rx_buffer[_rx_buffer_tail];
}
int Serial_read()
{
    if (_rx_buffer_head == _rx_buffer_tail)
    {
        return -1;
    }
    else
    {
        unsigned char c = _rx_buffer[_rx_buffer_tail];
        _rx_buffer_tail = (uint8_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
        return c;
    }
}
#elif ECBM_UART1_RECEIVE_CALLBACK_EN
void uart1_receive_callback() {}
#endif // UART_RECEIVE_EN
// =========================================================== Millis
#if MILLIS_EN
#if (ECBM_TIMER_LIB_EN && ECBM_TIMER0_EN) == 0
#error Config error, please modify the settings!
#endif
uint32_t _millis_count = 0;
void time0_fun(void) interrupt 1 { _millis_count++; }
void time0_init(void)
{
    timer_init();
    timer_set_value(0, 0);
    timer_set_timer_mode(0, 1000);
    timer_start(0);
}
uint32_t millis(void) { return _millis_count; }
#endif // MILLIS_EN
// =========================================================== EEPROM
#if EEPROM_EN
#if (ECBM_EEPROM_LIB_EN) == 0
#error Config error, please modify the settings!
#endif
#if ECBM_EEPROM_EX_EN
#warning Enabling ECBM_EEPROM_EX_EN will occupy 512 bytes xdata!
#endif
#if 1 // ----------------------------------- >> eeprom_put
void eeprom_put(void *pointer, size_t count)
{
    size_t i;
    const char *p = (const char *)pointer;
    eeprom_erase(0);
    for (i = 0; i < count; i++)
    {
        eeprom_write(i, p[i]);
    }
}
void eeprom_get(void *pointer, size_t count)
{
    uint16_t i;
    char *p = (char *)pointer;
    for (i = 0; i < count; i++)
    {
        p[i] = eeprom_read(i);
    }
}
#endif
#endif // MILLIS_EN
// =========================================================== Main
void setup(void);
void loop(void);

void main(void)
{
    system_init();
#if MILLIS_EN
    time0_init();
#endif
#if EEPROM_EN
    eeprom_init();
#endif
#if ANALOG_READ_EN
    adc_init();
#endif
#if ANALOG_WRITE_EN
    pca_init();
    pca_set_io(PCA_PIN_P13_P11_P10_P37);
    pca_set_mode(0, 3); // CCP0~CCP3 , <3>8位PWM模式
    pca_set_mode(1, 3); // CCP0~CCP3 , <3>8位PWM模式
    pca_set_mode(2, 3); // CCP0~CCP3 , <3>8位PWM模式
#endif
    setup();
    while (1)
        loop();
}
// =========================================================== Math
#define BIN 2
#define DEC 10
#define HEX 16
#define PI 3.1415926535897932384626433832795

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define abs(x) ((x) > 0 ? (x) : -(x))
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
#define round(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x) * (x))
#define map(x, in_min, in_max, out_min, out_max) ((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)

#define byte(w) ((uint8_t)(w))
#define lowByte(w) ((uint8_t)((w)&0xff))
#define highByte(w) ((uint8_t)((w) >> 8))

#define bit(b) (1UL << (b))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

#define maskSet(value, mask) ((value) |= (mask))
#define maskClear(value, mask) ((value) &= ~(mask))
// =========================================================== Func
#if FUNC_STRING_EN
#if 1 // ----------------------------------- >> itoa
char *itoa(int n, uint8_t base)
{
    uint8_t len = 0;
    int _n = n;
    char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
    char *str = &buf[sizeof(buf) - 1];
    *str = '\0';
    n = abs(n); // !!!
    // prevent crash if called with base == 1
    if (base < 2)
        base = 10;
    do
    {
        char c = n % base;
        n /= base;
        *--str = c < 10 ? c + '0' : c + 'A' - 10;
        len++;
    } while (n);
    if (base == 16 && len % 2 == 1)
        *--str = '0';
    if (base == 10 && _n < 0)
        *--str = '-';
    return str;
}
#endif
#if 1 // ----------------------------------- >> atoi
int atoi(char *str)
{
    int val = 0;
    bool flag = 0;
    if (str[0] == '-')
    {
        flag = 1;
        str += 1;
    }
    while (*str >= '0' && *str <= '9')
    {
        val *= 10;
        val += *str - '0';
        str++;
    }
    return flag ? -val : val;
}
#endif
#endif // FUNC_STRING_EN
#if FUNC_MEMORY_EN
void memcopy(void *dst, const void *src, size_t count)
{
    int i;
    char *pdst = (char *)dst;
    const char *psrc = (const char *)src;
    if (dst == NULL || src == NULL || count < 0)
        return;
    if (dst == src)
        return;
    if (pdst > psrc && pdst < psrc + count)
    {
        for (i = count - 1; i >= 0; i--)
            pdst[i] = psrc[i];
    }
    else
    {
        for (i = 0; i < count; i++)
            pdst[i] = psrc[i];
    }
}
#endif // FUNC_MEMORY_EN
// =========================================================== End
#endif